package com.example.video.plateRecognition.infrastructure.manage;

import Common.ConfigFileUtil;
import com.example.video.common.util.HCNetBase;
import com.example.video.common.util.HikUtils;
import com.example.video.HCNetSDK;
import com.sun.jna.Pointer;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class VehicleManage extends HCNetBase {

    private final static Logger logger = LoggerFactory.getLogger(VehicleManage.class);

    static FVehicleCrtlCB fVehicleCrtlCB = null;
    static int iStatus = 0;

    public VehicleManage() {
        lUserID = -1;
    }

    //车辆授权名单批量下发
    public void addVehicleList(String plateNumber, LocalDateTime startTime ,LocalDateTime stopTime)  {
        if (fVehicleCrtlCB == null)
        {
            fVehicleCrtlCB = new FVehicleCrtlCB();
        }
        int lHandle = hCNetSDK.NET_DVR_StartRemoteConfig(lUserID, HCNetSDK.NET_DVR_VEHICLELIST_CTRL_START, null, 0, fVehicleCrtlCB, Pointer.NULL);
        if (lHandle <= -1) {
            System.out.println("NET_DVR_StartRemoteConfig failed errorCode:" + hCNetSDK.NET_DVR_GetLastError());
            return;
        }
        HCNetSDK.NET_DVR_VEHICLE_CONTROL_LIST_INFO struVehicleControl = new HCNetSDK.NET_DVR_VEHICLE_CONTROL_LIST_INFO();
        struVehicleControl.read();
        struVehicleControl.dwSize = struVehicleControl.size();
        struVehicleControl.dwChannel = 1; //通道号，出入口抓拍机，一体机默认1
        String sLicense = plateNumber;    //车牌号码
        try {
            struVehicleControl.sLicense = sLicense.getBytes("GBK"); //车牌号码
        }catch (UnsupportedEncodingException e) {
            logger.error("车牌号字符转换出错");
        }
        struVehicleControl.byListType = 0; //名单属性：0- 授权名单，1- 非授权名单
        struVehicleControl.byPlateType = 0; //0- 标准民用车与军车车牌  //参考SDK使用手册中车牌类型枚举类型
        /**
         * VCA_BLUE_PLATE
         * 0- 蓝色车牌
         * VCA_YELLOW_PLATE
         * 1- 黄色车牌
         * VCA_WHITE_PLATE
         * 2- 白色车牌
         * VCA_BLACK_PLATE
         * 3- 黑色车牌
         * VCA_GREEN_PLATE
         * 4- 绿色车牌
         * VCA_BKAIR_PLATE
         * 5- 民航黑色车牌
         * VCA_OTHER = 0xff
         * 0xff- 其他
         */
        struVehicleControl.byPlateColor = 0; //车牌颜色
        //有效开始时间
        struVehicleControl.struStartTime = HikUtils.getHkTimeV30(startTime);
        //有效结束时间
        struVehicleControl.struStopTime = HikUtils.getHkTimeV30(stopTime);
        struVehicleControl.write();
        boolean bSend = hCNetSDK.NET_DVR_SendRemoteConfig(lHandle, HCNetSDK.ENUM_SENDDATA, struVehicleControl.getPointer(), struVehicleControl.size());
        if (!bSend) {
            System.err.println("NET_DVR_SendRemoteConfig失败，错误码：" + hCNetSDK.NET_DVR_GetLastError());
            //关闭下发长连接
            hCNetSDK.NET_DVR_StopRemoteConfig(lHandle);
        }
    }

    //下发车牌授权名单状态回调函数
    static class FVehicleCrtlCB implements HCNetSDK.FRemoteConfigCallBack {
        public void invoke(int dwType, Pointer lpBuffer, int dwBufLen, Pointer pUserData) {
            switch (dwType) {
                case HCNetSDK.NET_SDK_CALLBACK_TYPE_STATUS:
                    HCNetSDK.BYTE_ARRAY struCallbackStatus = new HCNetSDK.BYTE_ARRAY(40);
                    struCallbackStatus.write();
                    Pointer pStatus = struCallbackStatus.getPointer();
                    pStatus.write(0, lpBuffer.getByteArray(0, struCallbackStatus.size()), 0, dwBufLen);
                    struCallbackStatus.read();

                    for (int i = 0; i < 4; i++) {
                        int ioffset = i * 8;
                        int iByte = struCallbackStatus.byValue[i] & 0xff;
                        iStatus = iStatus + (iByte << ioffset);
                    }
                    switch (iStatus) {
                        case HCNetSDK.NET_SDK_CALLBACK_STATUS_SUCCESS:// NET_SDK_CALLBACK_STATUS_SUCCESS
                        {
                            logger.info("下发成功");
                            //增加消息事件，查询成功之后调用NET_DVR_StopRemoteConfig释放资源
                            break;
                        }

                        case HCNetSDK.NET_SDK_CALLBACK_STATUS_PROCESSING:
                        {
                            logger.info("下发中...");
                            break;
                        }

                        case HCNetSDK.NET_SDK_CALLBACK_STATUS_FAILED:
                        {
                            logger.info("下发失败,错误码： dwStatus:" + iStatus);
                            //增加消息事件，查询失败之后调用NET_DVR_StopRemoteConfig释放资源
                            break;
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 查询车牌授权/非授权名单
     */
    public  String searchVehicleList(String plateNumber,int channel,int number)
    {
        String searchVechileListUrl = "POST /ISAPI/Traffic/channels/"+channel+"/searchLPListAudit";
        //输入参数，XML或者JSON数据,查询多条人员信息json报文
        Map<String, Object> parameter = new HashMap<>();
        parameter.put("searchID", UUID.randomUUID()); // 查询id
        parameter.put("maxResults", number); // 最大查询数量
        parameter.put("licensePlate", plateNumber); // 车牌号
        String strInbuff = ConfigFileUtil.getReqBodyFromTemplate("/conf/ITC/searchVechileList.xml", parameter);
        logger.info("查询的json报文:" + strInbuff);
        return stdXMLConfig(lUserID,searchVechileListUrl,strInbuff);
    }

    /**
     * 删除车辆授权/非授权名单
     */
    public  void deleteVehicleList(String plateNumber,int channel)
    {
        String deleteVechileListUrl = "PUT /ISAPI/Traffic/channels/"+channel+"/DelLicensePlateAuditData?format=json";
        //输入参数，XML或者JSON数据
        Map<String, Object> parameter = new HashMap<>();
        parameter.put("plateColor","blue"); // 车牌颜色
        parameter.put("licensePlate", plateNumber); // 车牌号
        String strInbuff = ConfigFileUtil.getReqBodyFromTemplate("/conf/ITC/DeleteVechileList.json", parameter);
        logger.info("删除车牌输入报文:" + strInbuff);
        String responseString = stdXMLConfig(lUserID,deleteVechileListUrl,strInbuff);
        logger.info("删除车牌返回报文："+responseString);
    }

    /**
     * 设备系统能力
     * @return
     */
    public String getDeviceSystemAbility(){
        String deviceSystemAbilityUrl = "GET /ISAPI/System/capabilities";
        String responseString = stdXMLConfig(lUserID,deviceSystemAbilityUrl,"");
        System.out.println("返回报文："+responseString);
        return responseString;
    }


    //  删除车牌授权名单输入报文
    public  String deleteXml()
    {
        Document document1;
        Element root = DocumentHelper.createElement("VCLDelCond");
        document1 = DocumentHelper.createDocument(root);
        Element delVCLCond = root.addElement("delVCLCond");
        delVCLCond.setText("1");
        Element plateNum = root.addElement("plateNum"); //车牌号
        plateNum.setText("皖A88888");
        Element plateColor = root.addElement("plateColor"); //车牌颜色
        plateColor.setText("0");
        Element plateType = root.addElement("plateType");  //车牌类型
        plateType.setText("0");
        Element cardNo = root.addElement("cardNo");  //卡号
        cardNo.setText("0");
        String requestXml = document1.asXML();
        return requestXml;
    }

    //查询车牌授权名单输入报文
    public String getXml()
    {
        Document document1;
        Element root = DocumentHelper.createElement("VCLDelCond");
        document1 = DocumentHelper.createDocument(root);
        Element getVCLNum = root.addElement("getVCLNum"); // 指定获取名单最大数量：由控件指定获取多少条数据
        getVCLNum.setText("10");
        Element startOffSet = root.addElement("startOffSet");  //指定名单搜索起始点
        startOffSet.setText("0");
        Element getVCLCond = root.addElement("getVCLCond");  //获取名单条件：0-全部，1-车牌号码，2-卡号，3-名单类型
        getVCLCond.setText("1");
        Element plateNum = root.addElement("plateNum"); //车牌号
        plateNum.setText("皖A88888");
        Element plateType = root.addElement("plateType");  //车牌类型  名单类型：0-授权名单，1-非授权
        plateType.setText("0");
        Element cardNo = root.addElement("cardNo");  //卡号
        cardNo.setText("0");
        String requestXml = document1.asXML();
        return requestXml;


    }


    /**
     * SDK透传ISAPI协议报文接口
     * @param lUserID
     * @param url
     * @param inputXml 输入报文
     * @return
     */
    public  String stdXMLConfig(int lUserID, String url, String inputXml) {

        //输入参数
        HCNetSDK.NET_DVR_XML_CONFIG_INPUT struXMLInput = new HCNetSDK.NET_DVR_XML_CONFIG_INPUT();
        struXMLInput.read();

        struXMLInput.dwSize = struXMLInput.size();

        HCNetSDK.BYTE_ARRAY stringRequest = new HCNetSDK.BYTE_ARRAY(1024);
        stringRequest.read();

        //输入ISAPI协议命令   批量查询人脸库命令：GET /ISAPI/Intelligent/FDLib
        System.arraycopy(url.getBytes(), 0, stringRequest.byValue, 0, url.length());
        stringRequest.write();
        struXMLInput.lpRequestUrl = stringRequest.getPointer();
        struXMLInput.dwRequestUrlLen = url.length();

        //输入XML文本，GET命令不传输入文本
        int inputDataLen = 0;
        try {
            inputDataLen = inputXml.getBytes("UTF-8").length;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        if(inputDataLen > 0)
        {
            HCNetSDK.BYTE_ARRAY stringInBuffer = new HCNetSDK.BYTE_ARRAY(inputDataLen);
            stringInBuffer.read();
            try {
                System.arraycopy(inputXml.getBytes("UTF-8"), 0, stringInBuffer.byValue, 0, inputDataLen);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            stringInBuffer.write();
            struXMLInput.lpInBuffer = stringInBuffer.getPointer();
            struXMLInput.dwInBufferSize = inputDataLen;
        }
        else
        {
            struXMLInput.lpInBuffer = null;
            struXMLInput.dwInBufferSize = 0;
        }

        struXMLInput.write();

        HCNetSDK.BYTE_ARRAY stringXMLOut = new HCNetSDK.BYTE_ARRAY(1024 * 1024);
        stringXMLOut.read();
        HCNetSDK.BYTE_ARRAY struXMLStatus = new HCNetSDK.BYTE_ARRAY(1024);
        struXMLStatus.read();

        HCNetSDK.NET_DVR_XML_CONFIG_OUTPUT struXMLOutput = new HCNetSDK.NET_DVR_XML_CONFIG_OUTPUT();
        struXMLOutput.read();
        struXMLOutput.dwSize = struXMLOutput.size();
        struXMLOutput.lpOutBuffer = stringXMLOut.getPointer();
        struXMLOutput.dwOutBufferSize = stringXMLOut.size();
        struXMLOutput.lpStatusBuffer = struXMLStatus.getPointer();
        struXMLOutput.dwStatusSize = struXMLStatus.size();
        struXMLOutput.write();

        if (!hCNetSDK.NET_DVR_STDXMLConfig(lUserID, struXMLInput, struXMLOutput)) {
            int iErr = hCNetSDK.NET_DVR_GetLastError();
            System.err.println("NET_DVR_STDXMLConfig失败，错误号: " + iErr + "，URL: " + url);
            return null;
        } else {
            stringXMLOut.read();
            System.out.println("输出文本大小：" + struXMLOutput.dwReturnedXMLSize);
            //打印输出XML文本
            String  strOutXML = new String(stringXMLOut.byValue).trim();
            //System.out.println(strOutXML);
            struXMLStatus.read();
            String strStatus = new String(struXMLStatus.byValue).trim();
            System.out.println(strStatus);

            return strOutXML;
        }
    }
}
